<template>
  <a-modal
      :confirmLoading="confirmLoading"
      :maskClosable="false"
      :title="title"
      :visible="visible"
      :width="720"
      @cancel="handleCancel"
      @ok="handleSubmit"
  >
    <a-spin :spinning="confirmLoading">
      <a-form :colon="false" :form="form">
        <!-- 渠道费率 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="渠道费率(%)">
          <a-input-number
              v-decorator="[
                'feeRate',
                { rules: [{ required: true, type: 'number', message: '请输入渠道费率(%)', trigger: 'blur' }] }
              ]"
              allow-clear
              placeholder="请输入渠道费率" style="width: 100%;"
          />
        </a-form-item>
        <!-- 开放平台 APPID -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="开放平台 APPID">
          <a-input
              v-decorator="[
              'config.appId',
              { rules: [{ required: true, message: '请输入开放平台上创建的应用的 APPID', trigger: 'blur' }] }
            ]"
              allow-clear placeholder="请输入开放平台 APPID"
          />
        </a-form-item>
        <!-- 渠道状态 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="渠道状态">
          <a-radio-group
              v-decorator="[
              'status',
              { initialValue: Status.ENABLED.key, rules: [{ required: true, message: '渠道状态不能为空', trigger: 'change' }] }
            ]"
          >
            <a-radio v-for="item in Status.data" :key="item.key" :value="item.key">
              {{ item.name }}
            </a-radio>
          </a-radio-group>
        </a-form-item>
        <!-- 网关地址 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="网关地址">
          <a-radio-group
              v-decorator="[
              'config.serverUrl',
              { rules: [{ required: true, message: '请传入网关地址', trigger: 'change' }] }
            ]"
          >
            <a-radio value="https://openapi.alipay.com/gateway.do">线上环境</a-radio>
            <a-radio value="https://openapi-sandbox.dl.alipaydev.com/gateway.do">沙箱环境</a-radio>
          </a-radio-group>
        </a-form-item>
        <!-- 签名算法类型 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="算法类型">
          <a-radio-group
              v-decorator="[
              'config.signType',
              { initialValue: 'RSA2', rules: [{ required: true, message: '请传入签名算法类型', trigger: 'change' }] }
            ]"
          >
            <a-radio value="RSA2">RSA2</a-radio>
          </a-radio-group>
        </a-form-item>
        <!-- 公钥类型选择 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="公钥类型">
          <a-radio-group
              v-decorator="[
              'config.mode',
              { initialValue: '1', rules: [{ required: true, message: '请传入公钥类型', trigger: 'change' }] }
            ]"
              @change="onModeChange"
          >
            <a-radio value="1">公钥模式</a-radio>
            <a-radio value="2">证书模式</a-radio>
          </a-radio-group>
        </a-form-item>

        <!-- 公钥模式表单项 -->
        <template v-if="form.getFieldValue('config.mode') === '1'">
          <!-- 应用私钥 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="应用私钥">
            <a-textarea
                v-decorator="[
                  'config.privateKey',
                  { rules: [{ required: true, message: '请输入商户私钥', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                :rows="4" allow-clear placeholder="请输入应用私钥"

            />
          </a-form-item>
          <!-- 支付宝公钥 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="支付宝公钥">
            <a-textarea
                v-decorator="[
                  'config.alipayPublicKey',
                  { rules: [{ required: true, message: '请输入支付宝公钥字符串', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                :rows="4" allow-clear placeholder="请输入支付宝公钥"
            />
          </a-form-item>
        </template>

        <!-- 证书模式表单项 -->
        <template v-else-if="form.getFieldValue('config.mode') === '2'">
          <!-- 应用私钥 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="应用私钥">
            <a-textarea
                v-decorator="[
                  'config.privateKey',
                  { rules: [{ required: true, message: '请输入商户私钥', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                :rows="4" allow-clear placeholder="请输入应用私钥"
            />
          </a-form-item>
          <!-- 商户公钥应用证书 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="商户公钥应用证书">
            <a-textarea
                v-decorator="[
                  'config.appCertContent',
                  { rules: [{ required: true, message: '请上传商户公钥应用证书', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                allow-clear placeholder="请上传商户公钥应用证书" read-only
            />
          </a-form-item>
          <!-- 商户公钥应用证书上传 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label=" ">
            <a-upload
                :accept="fileAccept"
                :before-upload="fileBeforeUpload"
                :custom-request="e => handleCertUpload(e, 'appCertContent')"
                action=""
            >
              <a-button>
                <a-icon type="upload"/>
                点击上传
              </a-button>
            </a-upload>
          </a-form-item>
          <!-- 支付宝公钥证书 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="支付宝公钥证书">
            <a-textarea
                v-decorator="[
                  'config.alipayPublicCertContent',
                  { rules: [{ required: true, message: '请上传支付宝公钥证书', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                allow-clear placeholder="请上传支付宝公钥证书" read-only
            />
          </a-form-item>
          <!-- 支付宝公钥证书上传 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label=" ">
            <a-upload
                :accept="fileAccept"
                :before-upload="fileBeforeUpload"
                :custom-request="e => handleCertUpload(e, 'alipayPublicCertContent')"
                action=""
            >
              <a-button>
                <a-icon type="upload"/>
                点击上传
              </a-button>
            </a-upload>
          </a-form-item>
          <!-- 根证书 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="根证书">
            <a-textarea
                v-decorator="[
                  'config.rootCertContent',
                  { rules: [{ required: true, message: '请上传指定根证书', trigger: 'blur' }] }
                ]"
                :autoSize="{ minRows: 8, maxRows: 8 }"
                allow-clear placeholder="请上传根证书" read-only
            />
          </a-form-item>
          <!-- 根证书上传 -->
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label=" ">
            <a-upload
                :accept="fileAccept"
                :before-upload="fileBeforeUpload"
                :custom-request="e => handleCertUpload(e, 'rootCertContent')"
                action=""
            >
              <a-button>
                <a-icon type="upload"/>
                点击上传
              </a-button>
            </a-upload>
          </a-form-item>
        </template>

        <!-- 接口内容加密方式 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="接口内容加密方式">
          <a-radio-group
              v-decorator="[
                  'config.encryptType',
                  { initialValue: 'NONE' , rules: [{ required: true, message: '请输入接口内容加密方式', trigger: 'change' }] }
              ]"
          >
            <a-radio value="NONE">无加密</a-radio>
            <a-radio value="AES">AES</a-radio>
          </a-radio-group>
        </a-form-item>
        <!-- 接口内容加密密钥 -->
        <template v-if="form.getFieldValue('config.encryptType') === 'AES'">
          <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="接口内容加密密钥">
            <a-input
                v-decorator="[
                'config.encryptKey',
                { rules: [{ required: true, message: '请输入接口内容加密密钥', trigger: 'blur' }] }
              ]"
                allow-clear placeholder="请输入接口内容加密密钥"
            />
          </a-form-item>
        </template>
        <!-- 备注 -->
        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="备注">
          <a-input v-decorator="['remark']" placeholder="请输入备注"/>
        </a-form-item>
      </a-form>
    </a-spin>
  </a-modal>
</template>

<script>
import * as Api from '@/api/pay/channel'
import StatusEnum from '@/common/enum/Status'
import _ from 'lodash'

export default {
  data() {
    // 默认config生成器
    const defaultConfig = () => ({
      appId: '',
      serverUrl: null,
      signType: 'RSA2',
      mode: 1,
      privateKey: '',
      alipayPublicKey: '',
      appCertContent: '',
      alipayPublicCertContent: '',
      rootCertContent: '',
      encryptType: 'NONE',
      encryptKey: ''
    })
    return {
      title: '',
      labelCol: {span: 7},
      wrapperCol: {span: 13},
      visible: false,
      confirmLoading: false,
      fileAccept: '.crt',
      form: this.$form.createForm(this),
      // 当前表单数据
      record: {
        appId: '',
        code: '',
        status: undefined,
        feeRate: undefined,
        remark: '',
        config: defaultConfig()
      },
      defaultConfig
    }
  },
  computed: {
    Status() {
      return StatusEnum
    }
  },
  methods: {
    // 打开弹窗并初始化表单
    show(appId, code) {
      this.visible = true
      this.resetForm(appId, code)
      Api.detail(undefined, {appId, code}).then(data => {
        if (data && data.id) {
          this.record = data
          // config从字符串转对象，合并默认值，兼容老数据
          this.record.config = Object.assign(this.defaultConfig(), JSON.parse(this.record.config || '{}'))
          this.title = '编辑支付渠道'
          this.setFieldsValue()
        } else {
          this.record.config = this.defaultConfig()
          this.title = '创建支付渠道'
        }
      })
    },
    // 设置表单初始值
    setFieldsValue() {
      this.$nextTick(() => {
        const pickKeys = [
          'feeRate', 'config.appId', 'status', 'config.serverUrl', 'config.signType',
          'config.mode', 'config.privateKey', 'config.alipayPublicKey', 'config.appCertContent',
          'config.alipayPublicCertContent', 'config.rootCertContent', 'config.encryptType',
          'config.encryptKey', 'remark'
        ]
        // 先抽取所有数据
        const values = _.pick(this.record, pickKeys)
        values['config']['mode'] = values['config']['mode'] || '1'
        values['config']['signType'] = values['config']['signType'] || 'RSA2'
        values['config']['encryptType'] = values['config']['encryptType'] || 'AES'

        // 1. 先设置 mode 字段，确保 mode 相关表单项渲染
        this.form.setFieldsValue({
          'config.mode': values['config']['mode']
        })

        // 2. 等表单项渲染完毕，再设置其它字段
        this.$nextTick(() => {
          // 只设置当前 mode 下会被渲染的字段
          const mode = values['config']['mode']
          const commonFields = {
            'feeRate': values['feeRate'],
            'config.appId': values['config']['appId'],
            'status': values['status'],
            'config.serverUrl': values['config']['serverUrl'],
            'config.signType': values['config']['signType'],
            'config.encryptType': values['config']['encryptType'],
            'config.encryptKey': values['config']['encryptKey'],
            'remark': values['remark'],
            'config.privateKey': values['config']['privateKey']
          }
          let modeFields = {}
          if (mode === '1' || mode === 1) {
            modeFields = {
              'config.alipayPublicKey': values['config']['alipayPublicKey']
            }
          } else if (mode === '2' || mode === 2) {
            modeFields = {
              'config.appCertContent': values['config']['appCertContent'],
              'config.alipayPublicCertContent': values['config']['alipayPublicCertContent'],
              'config.rootCertContent': values['config']['rootCertContent']
            }
          }
          this.form.setFieldsValue({
            ...commonFields,
            ...modeFields
          })
        })
      })
    },
    // 重置表单数据
    resetForm(appId, code) {
      this.record = {
        appId,
        code,
        status: this.Status.ENABLED.key,
        remark: '',
        feeRate: null,
        config: this.defaultConfig()
      }
      this.$nextTick(() => {
        this.form.resetFields()
      })
    },
    // 表单提交
    handleSubmit(e) {
      e.preventDefault()
      this.form.validateFields((errors, values) => {
        if (!errors) {
          this.onFormSubmit(values)
        }
      })
    },
    // 关闭弹窗
    handleCancel() {
      this.visible = false
      this.form.resetFields()
    },
    // 表单提交到后端
    onFormSubmit(values) {
      this.confirmLoading = true
      const params = {...this.record, ...values}
      params.config = JSON.stringify(params.config || {})
      const api = this.record && this.record.id ? Api.edit(this.record.id, params) : Api.add(params)
      api
          .then(() => {
            this.$message.success('操作成功', 1.5)
            this.handleCancel()
            this.$emit('handleSubmit', params)
          })
          .finally(() => {
            this.confirmLoading = false
          })
    },
    // 上传前校验文件格式及大小
    fileBeforeUpload(file) {
      const ext = '.' + file.name.split('.').pop()
      if (ext !== this.fileAccept) {
        this.$message.error(`请上传指定格式"${this.fileAccept}"文件`)
        return false
      }
      const isRightSize = file.size / 1024 / 1024 < 2
      if (!isRightSize) {
        this.$message.error('文件大小超过 2MB')
      }
      return isRightSize
    },
    // 证书上传并写入表单
    handleCertUpload(event, certField) {
      const readFile = new FileReader()
      readFile.onload = e => {
        this.record.config[certField] = e.target.result
        this.form.setFieldsValue({
          [`config.${certField}`]: e.target.result
        })
        // 关键：通知上传成功，结束 loading
        event.onSuccess && event.onSuccess()
      }
      readFile.readAsText(event.file)
    },
    // 切换公钥/证书模式时，清空不相关表单项，避免校验报错
    onModeChange(e) {
      const mode = e.target.value
      if (mode === 1) {
        // 清空证书相关
        this.form.setFieldsValue({
          'config.appCertContent': undefined,
          'config.alipayPublicCertContent': undefined,
          'config.rootCertContent': undefined
        })
      } else if (mode === 2) {
        // 清空公钥相关
        this.form.setFieldsValue({
          'config.alipayPublicKey': undefined
        })
      }
    }
  }
}
</script>

<style lang="less" scoped>
/deep/ .ant-form-item {
  margin-bottom: 18px !important;
}
</style>